/*
* Copyright 2010 Pavel Kozhin 
*
* Licensed under the Apache License, Version 2.0 (the "License"); 
* you may not use this file except in compliance with the License. 
* You may obtain a copy of the License at 
* 
* http://www.apache.org/licenses/LICENSE-2.0
* 
* Unless required by applicable law or agreed to in writing, software 
* distributed  under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
* See the License for the specific language governing permissions and 
* limitations under the License.
*
* Author: Pavel Kozhin.
*/

package org.bookmarksframework.browser
{
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.external.ExternalInterface;
	
	import mx.events.BrowserChangeEvent;
	import mx.managers.IBrowserManager;
	
	import org.bookmarksframework.BookmarksConfig;
	
	[Event(name="change", type="flash.event.Event")]
	
	[Event(name="internalChange", type="flash.event.Event")]
	
	[Event(name="externalChange", type="flash.event.Event")]
	
	public class BrowserManagerAdapter extends EventDispatcher implements IBrowserAdapter
	{
		protected var adoptee:IBrowserManager;
		
		protected var config:BookmarksConfig;
		
		protected var pathQualifier:String = "/";
		
		protected var initialized:Boolean = false;
		
		protected var useStrictPath:Boolean = false;
		
		public function BrowserManagerAdapter(adoptee:Object)
		{
			this.adoptee = IBrowserManager(adoptee);
		}
		
		public function get fragment():String
		{
			checkInitialization();
			return qualify(unescape(adoptee.fragment));
		}
		
		public function set fragment(value:String):void
		{
			checkInitialization();
			adoptee.setFragment(qualify(value));
			
			lengthChanged = true;
			
			if (hasEventListener("lengthChanged"))
				dispatchEvent(new Event("lengthChanged"));
		}
		
		public function get title():String
		{
			checkInitialization();
			return adoptee.title;
		}
		
		public function set title(value:String):void
		{
			checkInitialization();
			adoptee.setTitle(value);
		}
		
		public function getURL():String
		{
			checkInitialization();
			return adoptee.url;
		}
		
		public function initialize(config:BookmarksConfig, 
								   fragment:String = "", title:String = ""):void
		{
			if (!adoptee)
				throw new Error("Bookmarks Error: Adoptee can't be null.");
			
			this.config = config;
			useStrictPath = config.useStrictPath;
			adoptee = IBrowserManager(adoptee);
			checkInitialization();
			
			adoptee.addEventListener(BrowserChangeEvent.APPLICATION_URL_CHANGE, 
				internalChangeHandler);
			adoptee.addEventListener(BrowserChangeEvent.URL_CHANGE, 
				changeHandler);
			adoptee.addEventListener(BrowserChangeEvent.BROWSER_URL_CHANGE, 
				externalChangeHandler);
			
			adoptee.init(fragment, title);
		}
		
		public function isFragmentEmpty():Boolean
		{
			var fragment:String = this.fragment;
			return !fragment || (useStrictPath && fragment == pathQualifier);
		}
		
		public function destroy():void
		{
			adoptee.removeEventListener(BrowserChangeEvent.APPLICATION_URL_CHANGE, 
				internalChangeHandler);
			adoptee.removeEventListener(BrowserChangeEvent.URL_CHANGE, 
				changeHandler);
			adoptee.removeEventListener(BrowserChangeEvent.BROWSER_URL_CHANGE, 
				externalChangeHandler);
			initialized = false;
			adoptee = null;
		}
		
		public function forward():void
		{
			ExternalInterface.call(
				"function(){return window.history.forward();}");
		}
		
		public function back():void
		{
			ExternalInterface.call(
				"function(){return window.history.back();}");
		}
		
		public function go(value:int):void
		{
			ExternalInterface.call(
				"function(){return window.history.go(" + value + ");}");
		}
		
		private var lengthChanged:Boolean = true;
		private var _length:Number = 0;
		
		[Bindable("lengthChanged")]
		public function get length():Number
		{
			checkInitialization();
			
			if (initialized && lengthChanged)
			{
				_length  = ExternalInterface.call(
					"function(){return window.history.length;}");
				lengthChanged = false;
			}
			
			return _length;
		}
		
		protected function changeHandler(event:BrowserChangeEvent):void
		{
			if (hasEventListener(BrowserAdapterEvents.CHANGE))
				dispatchEvent(new Event(BrowserAdapterEvents.CHANGE));
		}
		
		protected function internalChangeHandler(event:BrowserChangeEvent):void
		{
			if (hasEventListener(BrowserAdapterEvents.INTERNAL_CHANGE))
				dispatchEvent(new Event(BrowserAdapterEvents.INTERNAL_CHANGE));
		}
		
		protected function externalChangeHandler(event:BrowserChangeEvent):void
		{
			if (hasEventListener(BrowserAdapterEvents.EXTERNAL_CHANGE))
				dispatchEvent(new Event(BrowserAdapterEvents.EXTERNAL_CHANGE));
		}
		
		protected function qualify(fragment:String):String
		{
			if (useStrictPath && fragment.indexOf(pathQualifier) != 0)
				fragment = pathQualifier + fragment;
			
			return fragment;
		}
		
		protected function checkInitialization():void
		{
			if (!initialized)
			{
				initialized = ExternalInterface.available;
				if (!initialized)
					trace("Bookmarks Error: BrowserManager is not initialized.");
			}
		}
			
	}
}